package cn.xinfei.xdecision.manager.web.aop;

import cn.hutool.json.JSONUtil;
import cn.xinfei.xdecision.common.model.login.AccountSessionWrap;
import cn.xinfei.xdecision.common.model.login.SessionManager;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.util.DateUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 日志打印切面
 */
@Slf4j
@Order(1)
@Aspect
@Component
public class LogAspect {
    private static final String EDP = "execution(* cn.xinfei.xdecision..controller..*.*(..))";

    @Around(EDP)
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();

        AccountSessionWrap session = SessionManager.getSession();
        String traceId = session.getTraceId();

        long startTime = System.currentTimeMillis();
        JSONObject logInfo = new JSONObject();
        try {
            log.info("**********   REQUEST START [" + traceId + "] **********");
            log.info("RequestURI:" + request.getRequestURI());
            logInfo.put("traceId", traceId);
            logInfo.put("request_time", DateUtils.getCurrentLocalDateTimeMs());
            logInfo.put("request_uri", request.getRequestURI());
            logInfo.put("request_body", getParam(pjp.getArgs(), methodSignature.getParameterNames()));

            Object retVal = pjp.proceed();

            logInfo.put("response_body", retVal.toString().length() > 1024 ? retVal.toString().substring(0, 1024) : retVal);

            return retVal;
        } catch (ApiException apiException) {
            throw apiException;
        } finally {
            long endTime = System.currentTimeMillis();
            logInfo.put("response_time", DateUtils.getCurrentLocalDateTimeMs());
            logInfo.put("duration", endTime - startTime);
            log.info(JSON.toJSONString(logInfo));
            log.info("**********   REQUEST END  [" + traceId + "] **********");
        }

    }

    private String getParam(Object[] fieldValues, String[] filedNames) {
        if (fieldValues == null
                || fieldValues.length == 0
                || filedNames == null
                || filedNames.length == 0
                || fieldValues.length != filedNames.length) {
            return null;
        }
        StringBuilder stringBuffer = new StringBuilder();
        for (int i = 0; i < fieldValues.length; i++) {
            if (fieldValues[i] instanceof HttpServletRequest
                    || fieldValues[i] instanceof MultipartRequest
                    || fieldValues[i] instanceof HttpServletResponse
                    || fieldValues[i] instanceof HttpSession) {
                continue;
            }
            stringBuffer.append("{");
            stringBuffer.append(filedNames[i]);
            stringBuffer.append(":");
            stringBuffer.append(JSONUtil.toJsonStr(fieldValues[i]));
            stringBuffer.append("},");
        }
        return stringBuffer.toString();
    }

}
